import {Component, OnInit, ViewChild} from '@angular/core';
import {FormControl, FormGroup, Validators} from "@angular/forms";
import {BarnProject} from "../../project/entity/barn-project";
import {BarnProduct} from "../../product/entity/barn-product";
import {Constants} from "../../../../../tools";
import {ProductService} from "../../product/service/product.service";
import * as DecoupledEditor from "src/assets/ckeditor5-build-decoupled-document/ckeditor.js"
import {forkJoin, Observable} from "rxjs";
import {NzModalService} from "ng-zorro-antd/modal";
import {PicUploadComponent} from "../../../../common-components/pic-upload/pic-upload/pic-upload.component";
import {BarnDocument} from "../entity/barn-document";
import {BarnDocumentService} from "../service/barn-document.service";
import {NzMessageService} from "ng-zorro-antd/message";
import {ActivatedRoute} from "@angular/router";
import {fromPromise} from "rxjs/internal/observable/innerFrom";
import {tap} from "rxjs/operators";

@Component({
  selector: 'app-edit-document',
  templateUrl: './edit-document.component.html',
  styleUrls: ['./edit-document.component.less']
})
export class EditDocumentComponent implements OnInit {
  validateForm = new FormGroup({
    documentTitle: new FormControl(null, [Validators.required, Validators.maxLength(20)]),
    productId: new FormControl(null, [Validators.required]),
    pid: new FormControl(null)
  })

  fullScreen = false

  isVisible = false;
  loading = false

  editor;

  @ViewChild("editor", {static: true})
  editorHolder;
  @ViewChild("toolBar", {static: true})
  toolbar


  projects: BarnProject[] = []
  allProducts: BarnProduct[] = []

  imgIds: string[] = []

  constructor(private productService: ProductService, private modalService: NzModalService, private documentService: BarnDocumentService,
              private msg: NzMessageService, private routeInfo: ActivatedRoute) {

  }

  ngOnInit(): void {
    const param = new BarnProduct();
    param.enable = Constants.Enable.YES
    this.productService.query(param).subscribe(value => {
      this.allProducts = value.data
    })
    const pid = this.routeInfo.snapshot.queryParams["pid"];
    let getById$ = null
    if (pid) {
      this.loading = true
      getById$ = this.documentService.getById(pid)
        .pipe(tap(value => {
          this.loading = false
          this.validateForm.patchValue(value);
          this.projects = value.projects || [];
          this.imgIds = value.imgIds || []
        }))
    }


    const editorPromise = this.initEditor()
    if (pid) {
      const editor$ = fromPromise(editorPromise);
      forkJoin<any[]>([editor$, getById$]).subscribe(value => {
        const data = value[1]
        this.editor.setData(data['documentText'])
      });
    }
  }

  // 已经选择的 project ids
  get disabledIds(): string[] {
    return this.projects.map(value => value.pid)
  }

  // 产品id
  get productId() {
    return this.validateForm.get("productId").value
  }

  // 选中一个 project
  selectProject(project: BarnProject) {

    const p = this.projects.find(v => v.pid === project.pid);
    if (!p) {
      this.projects.push(project)
    }
    this.isVisible = false
  }

  // 删除一个
  deleteProject(index: number) {
    this.projects.splice(index, 1)
  }

  showPicSelect(callback): Observable<string> {
    this.modalService.create({
      nzTitle: "插入图片",
      nzContent: PicUploadComponent,
      nzStyle: {width: '800px'},
      nzOnOk: (data) => {
        if (typeof callback === "function" && data.srcArray && data.srcArray.length) {
          const urls = [];
          data.srcArray.forEach(value => {
            this.imgIds.push(value.id);
            urls.push({src: value.url, 'img-file-id': value.id})
          });
          callback(urls);
        }
      }
    })
    return null
  }

  submitForm(isRelease?: string) {
    const param = this.validateForm.getRawValue() as BarnDocument;
    param.documentText = this.editor.getData();
    param.isRelease = typeof isRelease === 'undefined' ? Constants.Enable.NO : Constants.Enable.YES;
    param.imgIds = this.imgIds;
    param.projectIds = this.projects.map(v => v.pid)
    param.documentPlainText = DecoupledEditor.viewToPlainText(this.editor.editing.view.document.getRoot())
    this.loading = true
    this.documentService.save(param).subscribe(value => {
      this.validateForm.patchValue(value)
      this.msg.success("保存成功")
      this.loading = false
    }, () => this.loading = false)
  }

  initEditor() {

    return DecoupledEditor
      .create(this.editorHolder.nativeElement, {typing: {}})
      .then(editor => {
        const toolbarContainer = this.toolbar.nativeElement;
        toolbarContainer.appendChild(editor.ui.view.toolbar.element);
        this.editor = editor;
        // 当点击插入图片时的回调方法
        this.editor.insertImageClick = (callback) => this.showPicSelect(callback)

        // 事件  https://github.com/ckeditor/ckeditor5/issues/1346
        // 另一个例子  https://github.com/shibbirweb/ckeditor5-image-remove-event-callback-plugin
        // 删除图片
        this.editor.editing.downcastDispatcher.on("remove:image", (evt, data, conversionApi) => {
          const viewPosition = conversionApi.mapper.toViewPosition(data.position);

          // Here it would be good to actually "look right" until the image element is found, because there
          // might be some empty elements or UI elements between `viewPosition` and the image.
          const viewElement = viewPosition.nodeAfter;
          const modelElement = conversionApi.mapper.toModelElement(viewElement);

          // Check if the image was actually removed.
          if (modelElement.root.rootName == '$graveyard') {
            // Read model attributes from `modelElement`.
          }
          const id = modelElement._attrs.get('img-file-id');
          this.imgIds = this.imgIds.filter(value => value !== id)
        })

        // 插入图片事件
        this.editor.editing.downcastDispatcher.on("insert:image", (evt, data, conversionApi) => {
          const item = data.item;
          if (item && item._attrs) {
            const id = item._attrs.get('img-file-id');
            if (id) {
              const old = this.imgIds.find(value => value === id);
              if (!old) {
                this.imgIds.push(id);
              }
            }
          }
        })
      })
      .catch(err => {
        console.error(err);
      })
  }
}
